package com.example.disk.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.example.disk.domain.DirTree;
import com.example.disk.domain.FileDTO;
import com.example.disk.domain.FileVO;
import com.example.disk.domain.entity.File;
import com.example.disk.domain.entity.User;
import com.example.disk.mapper.FileMapper;
import com.example.disk.mapper.UserMapper;
import com.example.disk.obs.OBSAgent;
import com.example.disk.service.FileService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.disk.util.File_Util;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author auto
 * @since 2020-07-15
 */
@Service
public class FileServiceImpl extends ServiceImpl<FileMapper, File> implements FileService {

    @Autowired
    UserMapper userMapper;
    @Autowired
    FileMapper fileMapper;
    @Autowired
    File_Util getFileIdByPath;
    @Autowired
    OBSAgent obsAgent;
    // username = zhangshan  path = /abc/doc 主要是数据库操作部分

    /*
    *功能：返回目标目录下文件的信息
    * 完成时间:7.18 12:24
    * 完成人：李帅
    * 测试：测试通过  时间：7.18 17:05
    * */
    @Override
    public List<FileVO> getFileList(String username, String path) throws IOException {
        //得到目录id
        int dirId = getFileIdByPath.getId(path,username);
        System.out.println("dirID="+dirId);
        List<File> lists = fileMapper.selectList(new QueryWrapper<File>().eq("parent",dirId));

        List<FileVO> result = new ArrayList<>();
        for(File file:lists){
            FileVO fileVO = new FileVO();
            fileVO.setFlag(file.getFlag()).setExtension(file.getExtension()).setName(file.getName()).setFilepath(path).setSize(file.getSize());
            fileVO.setCreateTime(file.getUpdateTime()+"");
            //加入url，需要obs提供
            String url = obsAgent.getUrl(username,path,file.getName()+"."+file.getExtension());
            fileVO.setUrl(url);
            if(file.getFlag()==1){
                fileVO.setFlag(1);
            }else{
                fileVO.setFlag(0);
            }
            result.add(fileVO);
        }

        return result;
    }

    /*
    * 功能：根据类型的不同返回不同的文件结果
    * 完成人：李帅
    *完成时间：7.18 12:47
    * 测试：测试通过 实现：7.18 17:28
    * */
    @Override
    public List<FileVO> getFileListByType(String username, int type) throws IOException {
        List<FileVO> result = new ArrayList<>();
        List<File> lists=null;
        int user_id = userMapper.selectOne(new QueryWrapper<User>().eq("username",username)).getId();       //用户id
        switch (type){
            case 1:     //图片
                lists = fileMapper.selectList(new QueryWrapper<File>()
                        .eq("user_id",user_id)
                        .in("extension","jpg","jpeg","png","gif")
                        .eq("flag",0)
                );
                break;
            case 2:     //文档
                lists = fileMapper.selectList(new QueryWrapper<File>()
                        .eq("user_id",user_id)
                        .in("extension","docx","doc","ppt","pptx","xls","xlsx","css","csv","pdf","sql","zip","rar","chm","txt","js","html","json")
                        .eq("flag",0)
                );
                break;
            case 3:     //视频
                lists = fileMapper.selectList(new QueryWrapper<File>()
                        .eq("user_id",user_id)
                        .in("extension","mp4","avi")
                        .eq("flag",0)
                );
                break;
            case 4:     //音乐
                lists = fileMapper.selectList(new QueryWrapper<File>()
                        .eq("user_id",user_id)
                        .in("extension","mp3")
                        .eq("flag",0)
                );
                break;
            case 5:
                lists = fileMapper.selectList(new QueryWrapper<File>()
                        .eq("user_id",user_id)
                        .notIn("extension","jpg","jpeg","png","gif","docx","doc","ppt","pptx","xls",
                                "xlsx","css","csv","pdf","sql","zip","rar","chm","txt","js","html","json","mp4","avi",
                                "mp3")
                        .eq("flag",0)
                );
                break;
            case 6:
                lists = fileMapper.selectList(new QueryWrapper<File>()
                        .eq("user_id",user_id)
                        .eq("flag",0)
                        .eq("deleted",1)
                );
                break;
        }

        if(lists!=null)
            for(File file:lists){
                FileVO fileVO = new FileVO();
                fileVO.setFlag(file.getFlag()).setExtension(file.getExtension()).setName(file.getName()).setFilepath(getFileIdByPath.getPathById(file.getId())).setSize(file.getSize());
                fileVO.setCreateTime(file.getUpdateTime().toString());
                //加入url，需要obs提供，暂时不做
                String url = obsAgent.getUrl(username,getFileIdByPath.getPathById(file.getId()),file.getName()+"."+file.getExtension());
                fileVO.setUrl(url);
                result.add(fileVO);
            }
        return result;
    }
    /*
     * 功能：创建文件夹
     * 完成人：李帅
     *完成时间：7.18 13:00
     * 测试：测试成功 时间：7.18 17:35
     * 修改：增加判断是否重名操作
     * */
    @Override
    public boolean createDir(String username, String path, String dirName) {
        boolean flag = getFileIdByPath.isExist(username,path,dirName,"",false);
        if(flag) return false;  //创建失败，因为重名了
        int parentId = getFileIdByPath.getId(path,username);
        int userId = userMapper.selectOne(new QueryWrapper<User>().eq("username",username)).getId();

        //数据库中插入一条数据
        File file = new File();
        file.setFlag(1).setCreateTime(LocalDateTime.now()).setDeleted(0).setExtension("").setName(dirName)
                .setParent(parentId).setSize(0).setType("").setUpdateTime(LocalDateTime.now()).setUserId(userId);

        //Obs中创建一个文件夹  (待写)
        //   lishuai-test  /   test01
        obsAgent.makeDir(username,path,dirName);
        return fileMapper.insert(file)>0;
    }

    /*
     * 功能：保存文件
     * 完成人：李帅
     *完成时间：7.18 13:10
     * 测试：obs未测试 数据库测试通过 时间：7.18 18:06  bug：驼峰命名法
     * 修改：byte[]data   修改为文件类型MultipartFile
     * */
    @Override
    public boolean saveFile(String username, String path, MultipartFile multipartFile, String fileName) throws IOException {
        String extension = fileName.substring(fileName.lastIndexOf(".")+1);
        String noExtensionFileName = fileName.substring(0,fileName.lastIndexOf("."));

        //重名检测
        boolean flag = getFileIdByPath.isExist(username,path,noExtensionFileName,extension,true);
        System.out.println();
        if(flag) return false;  //创建失败，因为重名了

        int parentId = getFileIdByPath.getId(path,username);
        User user = userMapper.selectOne(new QueryWrapper<User>().eq("username",username));
        System.out.println(user);
        int userId = user.getId();

        //数据库中插入一条数据
        File file = new File();
        file.setFlag(0).setCreateTime(LocalDateTime.now()).setDeleted(0).setExtension(extension).setName(noExtensionFileName)
                .setParent(parentId).setSize((int)multipartFile.getSize()).setType(extension).setUpdateTime(LocalDateTime.now()).setUserId(userId);


        //修改用户的使用空间
        int last_size = user.getUsedSize();
        userMapper.update(new User().setUsedSize(last_size+(int)multipartFile.getSize()),new UpdateWrapper<User>().eq("id",userId));
        //Obs中添加文件（待写）
        obsAgent.storeFile(username,path,fileName,multipartFile.getInputStream());
        return fileMapper.insert(file)>0;
    }

    /*
     * 功能：删除文件
     * 完成人：李帅
     *完成时间：7.18 14:20
     * 测试：测试成功 时间：7.18 18:31 发现bug，名字相同而后缀不同的文件会报错，已解决
     * */
    @Override
    public boolean deleteFile(String username, String path, String filename, String extend) {
        //在数据库中删除
        int parent_id = getFileIdByPath.getId(path,username);

        //避免同名，后缀不同的文件
        int file_id = fileMapper.selectOne(new QueryWrapper<File>().eq("parent",parent_id).
                eq("extension",extend).eq("name",filename)).getId();
        //修改用户表
        File file = fileMapper.selectOne(new QueryWrapper<File>().eq("id",file_id));
        User user = userMapper.selectOne(new QueryWrapper<User>().eq("username",username));
        userMapper.update(new User().setUsedSize(user.getUsedSize()-file.getSize()),new UpdateWrapper<User>().eq("username",username));
        //Obs中不做任何处理
        return fileMapper.deleteById(file_id)>0;        //将对应的deleted改为1
    }

    /*
     * 功能：删除文件夹
     * 完成人：李帅
     *完成时间：7.18 14:45
     * 测试：层次删除通过 时间：7.18 19:25  bug：更新用户已经使用的大小时出错，后面解决
     * */
    @Override
    public boolean deleteDir(String username, String path, String dirName) {
        int parent_id = getFileIdByPath.getId(path,username);
        int root_id = fileMapper.selectOne(new QueryWrapper<File>().eq("parent",parent_id)
                .eq("flag",1).eq("name",dirName)).getId();
        //将对应的
        List<Integer> del_files = new ArrayList<>();
        List<Integer> temp = new ArrayList<>();
        List<Integer> temp_record = new ArrayList<>();
        del_files.add(root_id);
        temp.add(root_id);
        while (temp.size()!=0){
            for(Integer id: temp){
                List<File> files = fileMapper.selectList(new QueryWrapper<File>().eq("parent",id));
                for(File file:files){
                    del_files.add(file.getId());
                    temp_record.add(file.getId());
                }
            }
            temp.clear();
            for(Integer k:temp_record){
                temp.add(k);
            }
            temp_record.clear();
        }
        try{
            for(Integer id:del_files){
                fileMapper.deleteById(id);
            }
        }catch (Exception e){
            return false;
        }

        int user_id = userMapper.selectOne(new QueryWrapper<User>().eq("username",username)).getId();
        userMapper.update(new User().setUsedSize(getStorage(user_id)),new UpdateWrapper<User>().eq("username",username));
        return true;
    }

    /*
     * 功能：重命名文件
     * 完成人：李帅
     *完成时间：7.18 14:56
     * 测试：测试通过 时间：7.18 19:32
     * */
    @Override
    public boolean renameFile(String username, String path, String fileName, String extend, String newName) throws IOException {
        //重名检测
        boolean flag = getFileIdByPath.isExist(username,path,fileName,extend,true);
        if(flag) return false;  //创建失败，因为重名了

        int parent = getFileIdByPath.getId(path,username);

        fileMapper.update(new File().setName(newName),new UpdateWrapper<File>().eq("parent",parent).eq("name",fileName).eq("extension",extend));

        //obs进行相应操作
        obsAgent.renameFile(username,path,fileName,newName);
        return true;
    }

    /*
     * 功能：重命名文件夹
     * 完成人：李帅
     *完成时间：7.18 14:59
     * 测试：测试通过 时间：7.18 19:47
     * */
    @Override
    public boolean renameDir(String username, String path, String dirName, String newName) throws IOException {
        //重名检测
        boolean flag = getFileIdByPath.isExist(username,path,newName,"",false);
        if(flag) return false;  //创建失败，因为重名了

        int parent_id = getFileIdByPath.getId(path,username);

        fileMapper.update(new File().setName(newName),new UpdateWrapper<File>().eq("parent",parent_id).eq("name",dirName)
        .eq("flag",1));

        //obs进行相应操作
        obsAgent.renameFile(username,path,dirName,newName);
        return true;
    }


    /*
     * 功能：移动文件
     * 完成人：李帅
     *完成时间：7.18 15:07
     * 测试：测试通过  时间：7.18 20:21  比较坑的地方：mybatis plus自带的逻辑删除功能，删除后数据库中存在，但是取不到
     * */

    @Override
    public boolean moveFile(String username, String path, String filename, String extend, int aimId) throws IOException {
        boolean flag = true;
        if(extend.equals("null")){
            flag=false;
        }
        //得到目标文名字
        String aim_name = fileMapper.selectById(aimId).getName();
        String parentPath = getFileIdByPath.getPathById(aimId);
        String newPath="";
        if(aim_name.equals(username)) newPath="/";
        else if(parentPath.equals("/")) newPath="/"+aim_name;
        else newPath=getFileIdByPath.getPathById(aimId)+"/"+aim_name;



        boolean isnamerepeat = getFileIdByPath.isExist(username,newPath,filename,extend,flag);
        //重名检测
        if(isnamerepeat) return false;  //创建失败，因为重名了


        //数据库操作
        int parent_id = getFileIdByPath.getId(path,username);

        if(flag){   //为文件
            System.out.println("在文件实现");
            fileMapper.update(new File().setParent(aimId),new UpdateWrapper<File>().eq("parent",parent_id)
                    .eq("extension",extend).eq("name",filename));
            //Obs进行相关操作
            obsAgent.moveFile(username,path,newPath,filename+"."+extend);

        }else{      //为文件夹
            System.out.println("在文件夹实现");
            fileMapper.update(new File().setParent(aimId),new UpdateWrapper<File>().eq("parent",parent_id)
                    .eq("name",filename));
            //Obs进行相关操作
            obsAgent.moveDir(username,path,newPath,filename);
        }

        return true;
    }

    /*
     * 功能：复制文件
     * 完成人：李帅
     *完成时间：7.18 15:12
     * 测试：测试通过  时间：7.18 20:45
     * */
    @Override
    public boolean copyFile(String username, String path, String filename, String extend, String aimPath) throws IOException {
        //重名检测
        boolean flag = getFileIdByPath.isExist(username,aimPath,filename,extend,true);
        if(flag) return false;  //创建失败，因为重名了


        int aim_Id = getFileIdByPath.getId(aimPath,username);
        User user = userMapper.selectOne(new QueryWrapper<User>().eq("username",username));
        int userId = user.getId();
        int parent_id = getFileIdByPath.getId(path,username);
        System.out.println("aim_Id="+aim_Id+" parent_id="+parent_id);
        int file_id = fileMapper.selectOne(new QueryWrapper<File>().eq("parent",parent_id)
                .eq("extension",extend).eq("name",filename)).getId();
        int file_size = fileMapper.selectById(file_id).getSize();
        //数据库中插入一条数据
        File file = new File();
        file.setFlag(0).setCreateTime(LocalDateTime.now()).setDeleted(0).setExtension(extend).setName(filename)
                .setParent(aim_Id).setSize(file_size).setType(extend).setUpdateTime(LocalDateTime.now()).setUserId(userId);


        //修改用户空间大小
        userMapper.update(new User().setUsedSize(user.getUsedSize()+file_size),new UpdateWrapper<User>().eq("username",username));

        //Obs中复制文件文件（待写）
        obsAgent.moveFile(username,path,aimPath,filename);
        return fileMapper.insert(file)>0;
    }

    @Override
    public Object getFileTree(String username) {
        return null;
    }

    private DirTree fileToDirTree(File file){
        return new DirTree().setId(file.getId()).setDirname(file.getName());
    }

    @Override
    public Object getDirTree(String username) {
        //得到根目录
        int rootId = fileMapper.selectOne(new QueryWrapper<File>().eq("name",username)).getId();
        //得到主目录下的文件夹
        List<File> files = fileMapper.selectList(new QueryWrapper<File>().eq("flag",1)
                .eq("parent",rootId));

        if(files==null) return null;
        //得到主目录对应信息
        List<DirTree>tree = new ArrayList<>();
        DirTree root = new DirTree().setId(rootId).setDirname(username);
        List<DirTree>dirTrees = root.getChildren();
        List<DirTree>temp_first = new ArrayList<>();
        List<DirTree>temp_second = new ArrayList<>();
        for(File file:files){
            DirTree dt = fileToDirTree(file);
            dirTrees.add(dt);
            temp_first.add(dt);
        }

        //得这些目录进行遍历
        while (temp_first.size()!=0){
            for(DirTree dt:temp_first){
                //得到子节点
                List<File> file_temp = fileMapper.selectList(new QueryWrapper<File>().eq("flag",1)
                        .eq("parent",dt.getId()));

                //遍历得到的子节点
                for(File file:file_temp){
                    DirTree dt_temp = fileToDirTree(file);
                    dt.getChildren().add(dt_temp);
                    //记住下一层
                    temp_second.add(dt_temp);
                }
            }

            temp_first.clear();
            //更新
            for(DirTree dirTree:temp_second){
                temp_first.add(dirTree);
            }

            temp_second.clear();
        }

        tree.add(root);
        return tree;
    }

    /*
     * 功能：获得已经使用的空间
     * 完成人：李帅
     *完成时间：7.18 15:17
     * 测试：待测试
     * */
    @Override
    public Integer getStorage(int userId) {
        int size=0;
        List<File> files = fileMapper.selectList(new QueryWrapper<File>().eq("user_id",userId).eq("deleted",0));
        for(File file:files){
            size+=file.getSize();
        }
        return size;
    }

    /*
     * 功能：获得已经使用的空间
     * 完成人：李帅
     *完成时间：7.18 15:28
     * 测试：待测试  上线后再测试
     * */
    @Override
    public boolean batchDeleteFile(String username, FileDTO[] files) {
        for(FileDTO fileVO:files){
            if(fileVO.getFlag()==1){    //文件夹
                deleteDir(username,fileVO.getPath(),fileVO.getName());
            }else{      //文件
                deleteFile(username,fileVO.getPath(),fileVO.getName(),fileVO.getExtension());
            }
        }

        int userId = userMapper.selectOne(new QueryWrapper<User>().eq("username",username)).getId();
        userMapper.update(new User().setUsedSize(getStorage(userId)),new UpdateWrapper<User>().eq("username",username));
        return true;
    }

    @Override
    public void createRoot(String username, int user_id) {
        //数据库中插入
        fileMapper.insert(new File().setFlag(1).setParent(-1).setUserId(user_id).setName(username)
                .setCreateTime(LocalDateTime.now()).setUpdateTime(LocalDateTime.now()).setDeleted(0).setSize(0));

        //obs中创建
        obsAgent.makeRootDir(username);
    }

    @Override
    public List<FileVO> searchByName(String username,int user_id,String file_name) throws IOException {
        List<File> lists = fileMapper.selectList(new QueryWrapper<File>().eq("user_id",user_id)
                .like("name",file_name).eq("flag",0));

        List<FileVO> result = new ArrayList<>();
        for(File file:lists){
            FileVO fileVO = new FileVO();
            fileVO.setFlag(file.getFlag()).setExtension(file.getExtension()).setName(file.getName()).setFilepath(getFileIdByPath.getPathById(file.getId())).setSize(file.getSize());
            fileVO.setCreateTime(file.getUpdateTime()+"");
            //加入url，需要obs提供
            String url = obsAgent.getUrl(username,getFileIdByPath.getPathById(file.getId()),file.getName()+"."+file.getExtension());
            fileVO.setUrl(url);
            if(file.getFlag()==1){
                fileVO.setFlag(1);
            }else{
                fileVO.setFlag(0);
            }
            result.add(fileVO);
        }

        return result;
    }

    @Override
    public InputStream getInputStream(String username, String path, String filename) throws IOException {
        return obsAgent.getInputStream(username,path,filename);
    }

    @Override
    public boolean clearFile(String username, String filename, String extension, String path) {
        //数据库中删除
        int userId = userMapper.selectOne(new QueryWrapper<User>().eq("username",username)).getId();
        int parentId = getFileIdByPath.getId(path,username);
        fileMapper.update(new File().setDeleted(-1),new UpdateWrapper<File>().eq("parent",parentId)
                .eq("user_id",userId).eq("extension",extension));
        //obs中删除

        obsAgent.deleteFile(username,path,filename+"."+extension);
        return false;
    }

    //恢复到主目录下
    @Override
    public boolean restoreFile(String username, String filename, String extension, String path) throws IOException {
        //数据库恢复
        int userId = userMapper.selectOne(new QueryWrapper<User>().eq("username",username)).getId();
        int rootId = fileMapper.selectOne(new QueryWrapper<File>().eq("name",username)).getId();
        int parentId = getFileIdByPath.getId(path,username);
        fileMapper.update(new File().setDeleted(0).setUpdateTime(LocalDateTime.now()).setParent(rootId),new UpdateWrapper<File>().eq("parent",parentId)
                .eq("user_id",userId).eq("extension",extension));

        //obs修改路径  即为move操作
        obsAgent.moveFile(username,path,"/",filename+"."+filename);
        return false;
    }


    @Override
    public List<FileVO> getDeleteFile(String username) throws IOException {
        int userId = userMapper.selectOne(new QueryWrapper<User>().eq("username",username)).getId();
        List<File> lists = fileMapper.selectList(new QueryWrapper<File>().eq("deleted",1)
                .eq("flag",0).eq("user_id",userId));

        List<FileVO> result = new ArrayList<>();
        for(File file:lists){
            FileVO fileVO = new FileVO();
            String path = getFileIdByPath.getPathById(file.getId());
            fileVO.setFlag(file.getFlag()).setExtension(file.getExtension()).setName(file.getName()).setFilepath(path).setSize(file.getSize());
            fileVO.setCreateTime(file.getUpdateTime()+"");
            //加入url，需要obs提供
            String url = obsAgent.getUrl(username,path,file.getName()+"."+file.getExtension());
            fileVO.setUrl(url);
            if(file.getFlag()==1){
                fileVO.setFlag(1);
            }else{
                fileVO.setFlag(0);
            }
            result.add(fileVO);
        }

        return result;
    }

    @Override
    public File getFileById(int id) {
        return fileMapper.selectOne(new QueryWrapper<File>().eq("id",id));
    }

}
